module axi_bootrom#(
    parameter AXI_ID_WIDTH      = 4,
    parameter AXI_ADDR_WIDTH    = 32,
    parameter AXI_DATA_WIDTH    = 64,
    parameter AXI_USER_WIDTH    = 4
)(
    input     clk,    // Clock
    input     rst_n,  // Asynchronous reset active low
    output                         axi_arready  , 
    input                          axi_arvalid  , 
    input   [ AXI_ADDR_WIDTH-1:0]  axi_araddr   , 
    input   [2:0]                  axi_arprot   , 
    input   [ AXI_ID_WIDTH-1:0]    axi_arid     , 
    input   [ AXI_USER_WIDTH-1:0]  axi_aruser   , 
    input   [7:0]                  axi_arlen    , 
    input   [2:0]                  axi_arsize   , 
    input   [1:0]                  axi_arburst  , 
    input                          axi_arlock   , 
    input   [3:0]                  axi_arcache  , 
    input   [3:0]                  axi_arqos    , 
    input                          axi_rready   , 
    output                         axi_rvalid   , 
    output [1:0]                   axi_rresp    , 
    output [AXI_DATA_WIDTH-1:0]    axi_rdata    , 
    output                         axi_rlast    , 
    output [AXI_ID_WIDTH-1:0]      axi_rid      , 
    output [AXI_USER_WIDTH-1:0]    axi_ruser    , 
    output                         axi_awready  , 
    input                          axi_awvalid  , 
    input  [AXI_ADDR_WIDTH-1:0]    axi_awaddr   , 
    input  [2:0]                   axi_awprot   , 
    input  [AXI_ID_WIDTH-1:0]      axi_awid     , 
    input  [AXI_USER_WIDTH-1:0]    axi_awuser   , 
    input  [7:0]                   axi_awlen    , 
    input  [2:0]                   axi_awsize   , 
    input  [1:0]                   axi_awburst  , 
    input                          axi_awlock   , 
    input  [3:0]                   axi_awcache  , 
    input  [3:0]                   axi_awqos    , 
    output                         axi_wready   , 
    input                          axi_wvalid   , 
    input  [AXI_DATA_WIDTH-1:0]    axi_wdata    , 
    input  [AXI_DATA_WIDTH/8-1:0]  axi_wstrb    , 
    input                          axi_wlast    , 
    input  [AXI_USER_WIDTH-1:0]    axi_wuser    ,
    input                          axi_bready   , 
    output                         axi_bvalid   , 
    output [1:0]                   axi_bresp    , 
    output [AXI_ID_WIDTH-1:0]      axi_bid      , 
    output [AXI_USER_WIDTH-1:0]    axi_buser    
);

logic                        req;
logic [AXI_ADDR_WIDTH-1:0]   addr;
logic [AXI_DATA_WIDTH-1:0]   data;
logic [AXI_ID_WIDTH-1: 0 ]   ID;


wire ar_hs = axi_arvalid & axi_arready;
wire r_hs  = axi_rvalid  & axi_rready ;

logic [2:0] cur_state , nxt_state;

parameter IDLE = 3'b001,
          AR   = 3'b010,
          R    = 3'b100;

always@(posedge clk or negedge rst_n)
    if(~rst_n)
        cur_state <= IDLE;
    else
        cur_state <= nxt_state;

always@(*)begin
    case(cur_state)
        IDLE:if(axi_arvalid) nxt_state = AR;   else nxt_state = IDLE;
        AR:if(ar_hs)     nxt_state = R;    else nxt_state = AR;
        R: if(r_hs)      nxt_state = IDLE; else nxt_state = R;
        default:nxt_state = IDLE;
    endcase
end

always@(posedge clk or negedge rst_n)
    if(~rst_n)
        ID <= 'd0;
    else if(ar_hs) 
        ID <= axi_arid;

// ROM req
assign req     = ar_hs;
assign addr    = axi_araddr;
// AR
assign axi_arready = (cur_state == AR);
// R
assign axi_rvalid  = (cur_state == R );
assign axi_rdata   = data;
assign axi_ruser   = 'd0;
assign axi_rresp   = 'd0;
assign axi_rid     = ID;
assign axi_rlast   = 1'b1;
bootrom ROM(
   .clk_i   ( clk    ),
   .req_i   ( req    ),
   .addr_i  ( addr   ),
   .rdata_o ( data   )
);

// AW W B
assign  axi_awready   = 'd1;
assign  axi_wready    = 'd1;
assign  axi_bid       = 'd0;
assign  axi_bresp     = 'd3;
assign  axi_bvalid    = 'd1;
assign  axi_buser     = 'd0;
endmodule